package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"gopkg.in/mgo.v2/bson"
	"server/src/accesscontroller"
	"server/src/languageswitcher"
)

const AccessTokenKey string = "zyp20190128"
const SecondOfDay int64 = 24 * 60 * 60

type HttpListener struct {
	dbo          *DBOperation
	cfg          *Config
	langSwitcher *languageswitcher.LanguageSwitcher
	ac           *accesscontroller.AccessController
}

type ResponseT struct {
	ErrorCode   int    `json:"errcode"`
	CompanyId   int    `json:"companyid"`
	CompanyName string `json:"companyname"`
	TeamId      string `json:"teamid"`
	TeamName    string `json:"teamname"`
	UserType    int    `json:"usertype"`
	UserId      string `json:"userid"`
	UserName    string `json:"username"`
	AccessToken string `json:"accesstoken"`
	Phone       string `json:"phone"`
	NoDevice    bool   `json:"nodevice"`
	NoSite      bool   `json:"nosite"`
	WxId        string `json:"wxid"`
	WxName      string `json:"wxname"`
	WxHeadUrl   string `json:"wxheadurl"`
	Threshold1  int    `json:"threshold1"`
	Threshold2  int    `json:"threshold2"`
}

type LoginHistoryT struct {
	CompanyId int    `bson:"cid"`
	UserId    string `bson:"userid"`
	User      string `bson:"user"`
	UserName  string `bson:"name"`
	Date      int    `bson:"d"`
	Time      int    `bson:"t"`
	Ip        string `bson:"ip"`
	Address   string `bson:"addr"`
}

func ListenHttpService(cfg *Config, db *DBOperation) {
	listenter := HttpListener{}
	listenter.dbo = db
	listenter.cfg = cfg
	listenter.langSwitcher = languageswitcher.NewLanguageSwitcher(db.session, db.dbName)
	listenter.ac = accesscontroller.NewAccessController(listenter.dbo.session, listenter.dbo.dbName)
	listenter.listen(cfg.HttpsPort)
}

func (p *HttpListener) listen(port int) {
	sPort := ""
	var err error

	http.HandleFunc("/login", p.login)

	http.HandleFunc("/checkaccess", p.checkAccessToken)

	http.HandleFunc("/test", p.testInterface)

	http.HandleFunc("/customerlist", p.customerlist)

	go func() {
		sPort = fmt.Sprintf(":%d", p.cfg.HttpsPort)
		zLog(nil, "开始监听端口:", sPort, " HTTPS:", p.cfg.HTTPS)
		if p.cfg.HTTPS {
			err = http.ListenAndServeTLS(sPort, p.cfg.CertFile, p.cfg.KeyFile, nil)
		} else {
			err = http.ListenAndServe(sPort, nil)
		}
		if err != nil {
			zLog(nil, "监听端口", sPort, "失败:", err)
		}
	}()
}

func (p *HttpListener) login(w http.ResponseWriter, req *http.Request) {
	w.Header().Add("Access-Control-Allow-Origin", "*")

	if !p.checkTimeLine(&w) {
		return
	}

	var s string
	if req.Method != "POST" {
		s = p.makeResultStr(1002, "无效的访问方式", "en")
		w.Write([]byte(s))
		return
	}

	req.ParseForm()
	var user, password, language string

	user = req.FormValue("user")
	password = req.FormValue("pass")
	language = req.FormValue("language")
	if language == "" {
		language = "cn"
	}

	if (user == "") || (password == "") {
		s = p.makeResultStr(1003, "缺少必要的字段。", language)
		w.Write([]byte(s))
		return
	}

	errCode, customer := p.dbo.Login(user, password)
	if errCode != 0 {
		s = p.makeResultStr(1001, "用户名或密码错误", language)
		w.Write([]byte(s))
		return
	}

	var response ResponseT
	var token string
	var tokenExpire int64

	response.UserId = customer.UserId.Hex()
	response.UserType = customer.Usertype
	response.UserName = customer.Username
	response.CompanyId = customer.CompanyId
	response.CompanyName = customer.CompanyName
	response.TeamId = customer.TeamId
	response.TeamName = customer.TeamName
	response.Phone = customer.Phone
	response.NoDevice = customer.NoDevice
	response.NoSite = customer.NoSite
	response.WxId = customer.WxId
	response.WxName = customer.WxName
	response.WxHeadUrl = customer.WxHead
	response.Threshold1 = customer.Threshold1
	response.Threshold2 = customer.Threshold2

	token, tokenExpire = p.ac.GetToken(response.UserId)

	if token == "" || (time.Now().Unix()-tokenExpire) >= SecondOfDay {
		response.AccessToken = p.ac.CreateToken(AccessTokenKey)
	} else {

		response.AccessToken = token
	}

	response.ErrorCode = 0

	p.ac.SaveToken(response.UserId, response.AccessToken)

	go p.saveLoginHistory(user, req.RemoteAddr, &response)

	var buf []byte
	buf, _ = json.Marshal(response)
	w.Write(buf)
}

func (p *HttpListener) checkAccessToken(w http.ResponseWriter, req *http.Request) {
	w.Header().Add("Access-Control-Allow-Origin", "*")

	if !p.checkTimeLine(&w) {
		return
	}

	req.ParseForm()

	var s string
	userid := req.FormValue("userid")
	accesstoken := req.FormValue("accesstoken")
	if (userid == "") || (accesstoken == "") {
		s = p.makeResultStr(1003, "缺少必要的字段。", "cn")
		w.Write([]byte(s))
		return
	}

	if !bson.IsObjectIdHex(userid) || !p.dbo.checkAccessToken(userid, accesstoken) {
		s = p.makeResultStr(1006, "非法访问", "cn")
		w.Write([]byte(s))
		return
	}

	s = p.makeResultStr(0, "", "cn")
	w.Write([]byte(s))

}

func (p *HttpListener) testInterface(w http.ResponseWriter, req *http.Request) {
	s := `{"code":100000}`
	zLog(nil, "测试成功::", s)
	w.Write([]byte(s))
}

func (p *HttpListener) saveLoginHistory(user, ip string, response *ResponseT) {
	var lh LoginHistoryT
	currentTime := time.Now()

	lh.CompanyId = response.CompanyId
	lh.UserId = response.UserId
	lh.User = user
	lh.UserName = response.UserName
	lh.Ip = p.trimIP(ip)
	lh.Date = currentTime.Year()*10000 + int(currentTime.Month())*100 + currentTime.Day()
	lh.Time = currentTime.Hour()*10000 + currentTime.Minute()*100 + currentTime.Second()
	lh.Address = p.queryAddress(lh.Ip)

	p.dbo.saveLoginHistory(&lh)
}

func (p *HttpListener) makeResultStr(code int, msg string, lang string) string {
	if code == 0 {
		return `{"errcode":0}`
	} else {
		newmsg := p.langSwitcher.Get(code, lang)
		if newmsg == "" {
			newmsg = msg
		}
		return fmt.Sprintf(`{"errcode":%d,"msg":"%s"}`, code, newmsg)
	}
}

/*
func (p *HttpListener) errorText(id int, lang string) string {
	return p.langSwitcher.Get(id, lang)
}
*/

func (p *HttpListener) trimIP(ip string) string {
	index := strings.Index(ip, ":")
	if index >= 0 {
		ip = ip[0:index]
	}

	return ip
}

func (p *HttpListener) queryAddress(ip string) string {
	url := fmt.Sprintf("%s?ip=%s", p.cfg.IPQueryUrl, ip)
	resp, err := http.Get(url)
	if err == nil {
		buf, _ := ioutil.ReadAll(resp.Body)
		defer resp.Body.Close()

		var res map[string]map[string]string
		err = json.Unmarshal(buf, &res)
		if err == nil {
			ipMap := res[ip]
			addr := ipMap["country"]
			area := ipMap["area"]
			return addr + "-" + area
		}
	}

	return "地址查询失败"
}

func (p *HttpListener) checkTimeLine(w *http.ResponseWriter) bool {
	if p.cfg.Key == 0 {
		return true
	}

	t := time.Now().Unix()

	if t < p.cfg.Key {
		return true
	}

	s := `{"errcode": 3001, "msg": "无效请求"}`
	(*w).Write([]byte(s))

	return false
}
func (p *HttpListener) customerlist(w http.ResponseWriter, req *http.Request) {
	p.dbo.customerList("", "tky", 1)
}
